//
// Unihan Input Method
//
// Copyright © 2002-2007 Sun Wah Linux Ltd.
//
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
// USA
//
// $Id: demoim.c 757 2007-05-10 08:19:31Z roger $
//

#ifdef HAVE_CONFIG_H
#   include <config.h>
#endif

#include <unihan_im.h>
#include <unihan_im_keycodes.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <iconv.h>

typedef struct {
    char preedit[11];
    int len;
    int pos;
} SampleIMSessionData;

typedef struct {
    iconv_t gb_to_u8_cd;
} SampleIMDesktopData;

extern "C" {
int unihan_im_module_init(void);
void unihan_im_module_done(void);
int unihan_im_module_get_info(UnihanIMModuleArgList *args);
}

static int sampleim_init(UnihanIM *uim);
static int sampleim_done(UnihanIM *uim);
static int sampleim_create_session(UnihanIM *uim);
static int sampleim_destroy_session(UnihanIM *uim);
static int sampleim_handle_event(UnihanIM *uim, IMEvent *ev);
static int handle_key_event(UnihanIM *uim, IMKeyEvent *ev);
static int handle_focus_event(UnihanIM *uim, IMFocusEvent *ev);
static int handle_config_change_event(UnihanIM *uim, IMConfigChangeEvent *ev);
static int handle_switch_event(UnihanIM *uim, IMSwitchEvent *ev);
static char *gb18030_to_utf8(UnihanIM *uim, const char *orig);

int
unihan_im_module_init(void)
{
    /* The input module can do some initialization here */
    
    return TRUE;
}


void
unihan_im_module_done(void)
{
    /* The input module can do some finalization here */
    
    return;
}


int
unihan_im_module_get_info(UnihanIMModuleArgList *args)
{
    IMMethods *imm = NULL;
    IMInfo *iminfo1 = NULL, *iminfo2 = NULL;

    if (!args) return FALSE;
    while (args->id) {
        switch (args->id) {
            case UNIHAN_IM_API_VERSION:
                args->value = (void*)0x00020000;
                break;
            case UNIHAN_IM_MODULE_ID:
                /* The unique ID of the input module */
                args->value = strdup("sampleim");
                break;
            case UNIHAN_IM_MODULE_NAME:
                /* Human readable name of the input module */
                args->value = strdup("输入法实例模组");
                break;
            case UNIHAN_IM_MODULE_VERSION:
                /* Version of the input module */
                args->value = strdup("1.0");
                break;
            case UNIHAN_IM_MODULE_IM_LIST:
                /* List of input methods in this input
                ** module */
                imm = (IMMethods *)calloc(1, sizeof(IMMethods));
                iminfo1 = (IMInfo *)calloc(1, sizeof(IMInfo));
                iminfo2 = (IMInfo *)calloc(1, sizeof(IMInfo));

                /* define callback functions */
                imm->init = sampleim_init;
                imm->done = sampleim_done;
                imm->create_session = sampleim_create_session;
                imm->destroy_session = sampleim_destroy_session;
                imm->handle_event = sampleim_handle_event;
                /* other info of this input method */
                iminfo1->id = strdup("im1");
                iminfo1->name = strdup("输入法实例1");
                iminfo1->version = strdup("1.0");
                iminfo1->imUserData = NULL;
                iminfo1->methodTable = imm;
                iminfo1->next = NULL;

                iminfo2->id = strdup("im2");
                iminfo2->name = strdup("输入法实例2");
                iminfo2->version = strdup("1.0");
                iminfo2->imUserData = NULL;
                iminfo2->methodTable = (IMMethods *)calloc(1, sizeof(IMMethods));
                memcpy(iminfo2->methodTable, imm, sizeof(IMMethods));
                iminfo2->next = iminfo1;

                args->value = iminfo2;
                break;
        }
        ++args;
    }

    return TRUE;
}


static int
sampleim_init(UnihanIM *uim)
{
    char *locale = NULL;
    int err;
    
    uim->desktopUserData = NULL;

    err = uim->m->locale_get(uim, &locale);
    if (err == 0)
        uim->m->log(uim, UNIHAN_LOG_LEVEL_DEBUG, "user's locale is %s", locale);

    SampleIMDesktopData *dd = (SampleIMDesktopData *)uim->desktopUserData;
    dd->gb_to_u8_cd = iconv_open("UTF-8", "GB18030");

    return TRUE;
}


static int
sampleim_done(UnihanIM *uim)
{
    SampleIMDesktopData *dd = (SampleIMDesktopData *)uim->desktopUserData;

    iconv_close(dd->gb_to_u8_cd);
    free(uim->desktopUserData);

    return TRUE;
}


static int
sampleim_create_session(UnihanIM *uim)
{
    uim->sessionUserData = malloc(sizeof(SampleIMSessionData));
    memset(uim->sessionUserData, 0, sizeof(SampleIMSessionData));
    return TRUE;
}


static int
sampleim_destroy_session(UnihanIM *uim)
{
    free(uim->sessionUserData);
    return TRUE;
}


static int
sampleim_handle_event(UnihanIM *uim, IMEvent *ev)
{
    uim->m->log(uim, UNIHAN_LOG_LEVEL_DEBUG, "handle event for module %s, id %s", uim->module_id, uim->id);

    switch (ev->type) {
        case IM_KEY:
            return handle_key_event(uim, (IMKeyEvent*)ev);
        case IM_FOCUS:
            return handle_focus_event(uim, (IMFocusEvent*)ev);
        case IM_CONFIG_CHANGE:
            return handle_config_change_event(uim, (IMConfigChangeEvent*)ev);
        case IM_SWITCH:
            return handle_switch_event(uim, (IMSwitchEvent*)ev);
        case IM_NOTHING:
        default:
            break;
    }

    return FALSE;
}


static int
handle_key_event(UnihanIM *uim, IMKeyEvent *ev)
{
    int err;
    SampleIMSessionData *s = (SampleIMSessionData *)uim->sessionUserData;

    if (ev->modifier == 0 && ev->keyChar >= 'a' && ev->keyChar <= 'z') {
        if (s->len < 10) {
            s->preedit[s->len++] = ev->keyChar;
            uim->m->preedit_draw(uim, s->preedit, NULL);
        }
        return TRUE;
    } else if (ev->modifier == 0 && ev->keyCode == IM_VK_ENTER) {
        if (s->len == 0)
            return FALSE;

        if (!strcmp("nihao", s->preedit)) {
            char *str = strdup("你好");
            err = uim->m->commit_string(uim, str);

            // *** if you have data in GB18030, you should do this:
            //
            // err = uim->m->commit_string(uim, gb18030_to_utf8(uim, "GB18030 string"));
 
            if (err != 0) {
                /* some error occurred */
            }
            free(str);
            s->len = 0;
            memset(s->preedit, 0, 11);
            uim->m->preedit_erase(uim);
        }
        return TRUE;
    } else if (ev->modifier == 0 && ev->keyCode == IM_VK_ESCAPE) {
        if (s->len == 0)
            return FALSE;

        s->len = 0;
        memset(s->preedit, 0, 11);
        uim->m->preedit_erase(uim);
        return TRUE;
    } else if (ev->modifier == 0 && ev->keyCode == IM_VK_BACK_SPACE) {
        if (s->len == 0)
            return FALSE;

        --s->len;
        s->preedit[s->len] = '\0';
        uim->m->preedit_draw(uim, s->preedit, NULL);
        return TRUE;
    }

    return FALSE;
}


static int
handle_focus_event(UnihanIM *uim, IMFocusEvent *ev)
{
    if (ev->focused == TRUE) {
        /* the input area has received focus */
    } else {
        /* the input area lost focus */
    }
}


static int
handle_config_change_event(UnihanIM *uim, IMConfigChangeEvent *ev)
{
    uim->m->log(uim, UNIHAN_LOG_LEVEL_DEBUG, "config key %s has changed", ev->key);
}


static int
handle_switch_event(UnihanIM *uim, IMSwitchEvent *ev)
{
    if (ev->on == TRUE) {
        /* the user has switched on this input method */
    } else {
        /* the user has switched off this input method */
    }
}

static char *
gb18030_to_utf8(UnihanIM *uim, const char *orig)
{
    SampleIMDesktopData *dd = (SampleIMDesktopData *)uim->desktopUserData;
    char *u8 = NULL, *u8_head;
    const char *gb, *gb_head;
    size_t ibytes, obytes, orig_len;

    gb = gb_head = orig;
    orig_len = strlen(orig);
    ibytes = orig_len;
    if (!ibytes)
        return NULL;
    obytes = orig_len * 3;
    if (!obytes)
        return NULL;
    uim->m->mem_alloc(uim, obytes, (void **)&u8);
    u8_head = u8;

    uim->m->log(uim, UNIHAN_LOG_LEVEL_DEBUG, "gb18030_to_utf8(): ibytes = %d  obytes = %d", ibytes, obytes);

    iconv(dd->gb_to_u8_cd, (char **)&gb, &ibytes, &u8, &obytes);
    return u8_head;
}

// vi:ts=4:sw=4:nowrap:cin:expandtab
